/*!

 * EventEmitter2

 * https://github.com/hij1nx/EventEmitter2

 *

 * Copyright (c) 2013 hij1nx

 * Licensed under the MIT license.

 */

; !function (undefined) {



    var isArray = Array.isArray ? Array.isArray : function _isArray(obj) {

        return Object.prototype.toString.call(obj) === "[object Array]";

    };

    var defaultMaxListeners = 10;



    function init() {

        this._events = {};

        if (this._conf) {

            configure.call(this, this._conf);

        }

    }



    function configure(conf) {

        if (conf) {

            this._conf = conf;



            conf.delimiter && (this.delimiter = conf.delimiter);

            this._maxListeners = conf.maxListeners !== undefined ? conf.maxListeners : defaultMaxListeners;



            conf.wildcard && (this.wildcard = conf.wildcard);

            conf.newListener && (this.newListener = conf.newListener);

            conf.verboseMemoryLeak && (this.verboseMemoryLeak = conf.verboseMemoryLeak);



            if (this.wildcard) {

                this.listenerTree = {};

            }

        } else {

            this._maxListeners = defaultMaxListeners;

        }

    }



    function logPossibleMemoryLeak(count, eventName) {

        var errorMsg = '(node) warning: possible EventEmitter memory ' +

            'leak detected. ' + count + ' listeners added. ' +

            'Use emitter.setMaxListeners() to increase limit.';



        if (this.verboseMemoryLeak) {

            errorMsg += ' Event name: ' + eventName + '.';

        }



        if (typeof process !== 'undefined' && process.emitWarning) {

            var e = new Error(errorMsg);

            e.name = 'MaxListenersExceededWarning';

            e.emitter = this;

            e.count = count;

            process.emitWarning(e);

        } else {

            console.error(errorMsg);



            if (console.trace) {

                console.trace();

            }

        }

    }



    function EventEmitter(conf) {

        this._events = {};

        this.newListener = false;

        this.verboseMemoryLeak = false;

        configure.call(this, conf);

    }

    EventEmitter.EventEmitter2 = EventEmitter; // backwards compatibility for exporting EventEmitter property



    //

    // Attention, function return type now is array, always !

    // It has zero elements if no any matches found and one or more

    // elements (leafs) if there are matches

    //

    function searchListenerTree(handlers, type, tree, i) {

        if (!tree) {

            return [];

        }

        var listeners = [], leaf, len, branch, xTree, xxTree, isolatedBranch, endReached,

            typeLength = type.length, currentType = type[i], nextType = type[i + 1];

        if (i === typeLength && tree._listeners) {

            //

            // If at the end of the event(s) list and the tree has listeners

            // invoke those listeners.

            //

            if (typeof tree._listeners === 'function') {

                handlers && handlers.push(tree._listeners);

                return [tree];

            } else {

                for (leaf = 0, len = tree._listeners.length; leaf < len; leaf++) {

                    handlers && handlers.push(tree._listeners[leaf]);

                }

                return [tree];

            }

        }



        if ((currentType === '*' || currentType === '**') || tree[currentType]) {

            //

            // If the event emitted is '*' at this part

            // or there is a concrete match at this patch

            //

            if (currentType === '*') {

                for (branch in tree) {

                    if (branch !== '_listeners' && tree.hasOwnProperty(branch)) {

                        listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], i + 1));

                    }

                }

                return listeners;

            } else if (currentType === '**') {

                endReached = (i + 1 === typeLength || (i + 2 === typeLength && nextType === '*'));

                if (endReached && tree._listeners) {

                    // The next element has a _listeners, add it to the handlers.

                    listeners = listeners.concat(searchListenerTree(handlers, type, tree, typeLength));

                }



                for (branch in tree) {

                    if (branch !== '_listeners' && tree.hasOwnProperty(branch)) {

                        if (branch === '*' || branch === '**') {

                            if (tree[branch]._listeners && !endReached) {

                                listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], typeLength));

                            }

                            listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], i));

                        } else if (branch === nextType) {

                            listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], i + 2));

                        } else {

                            // No match on this one, shift into the tree but not in the type array.

                            listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], i));

                        }

                    }

                }

                return listeners;

            }



            listeners = listeners.concat(searchListenerTree(handlers, type, tree[currentType], i + 1));

        }



        xTree = tree['*'];

        if (xTree) {

            //

            // If the listener tree will allow any match for this part,

            // then recursively explore all branches of the tree

            //

            searchListenerTree(handlers, type, xTree, i + 1);

        }



        xxTree = tree['**'];

        if (xxTree) {

            if (i < typeLength) {

                if (xxTree._listeners) {

                    // If we have a listener on a '**', it will catch all, so add its handler.

                    searchListenerTree(handlers, type, xxTree, typeLength);

                }



                // Build arrays of matching next branches and others.

                for (branch in xxTree) {

                    if (branch !== '_listeners' && xxTree.hasOwnProperty(branch)) {

                        if (branch === nextType) {

                            // We know the next element will match, so jump twice.

                            searchListenerTree(handlers, type, xxTree[branch], i + 2);

                        } else if (branch === currentType) {

                            // Current node matches, move into the tree.

                            searchListenerTree(handlers, type, xxTree[branch], i + 1);

                        } else {

                            isolatedBranch = {};

                            isolatedBranch[branch] = xxTree[branch];

                            searchListenerTree(handlers, type, { '**': isolatedBranch }, i + 1);

                        }

                    }

                }

            } else if (xxTree._listeners) {

                // We have reached the end and still on a '**'

                searchListenerTree(handlers, type, xxTree, typeLength);

            } else if (xxTree['*'] && xxTree['*']._listeners) {

                searchListenerTree(handlers, type, xxTree['*'], typeLength);

            }

        }



        return listeners;

    }



    function growListenerTree(type, listener) {



        type = typeof type === 'string' ? type.split(this.delimiter) : type.slice();



        //

        // Looks for two consecutive '**', if so, don't add the event at all.

        //

        for (var i = 0, len = type.length; i + 1 < len; i++) {

            if (type[i] === '**' && type[i + 1] === '**') {

                return;

            }

        }



        var tree = this.listenerTree;

        var name = type.shift();



        while (name !== undefined) {



            if (!tree[name]) {

                tree[name] = {};

            }



            tree = tree[name];



            if (type.length === 0) {



                if (!tree._listeners) {

                    tree._listeners = listener;

                }

                else {

                    if (typeof tree._listeners === 'function') {

                        tree._listeners = [tree._listeners];

                    }



                    tree._listeners.push(listener);



                    if (

                      !tree._listeners.warned &&

                      this._maxListeners > 0 &&

                      tree._listeners.length > this._maxListeners

                    ) {

                        tree._listeners.warned = true;

                        logPossibleMemoryLeak.call(this, tree._listeners.length, name);

                    }

                }

                return true;

            }

            name = type.shift();

        }

        return true;

    }



    // By default EventEmitters will print a warning if more than

    // 10 listeners are added to it. This is a useful default which

    // helps finding memory leaks.

    //

    // Obviously not all Emitters should be limited to 10. This function allows

    // that to be increased. Set to zero for unlimited.



    EventEmitter.prototype.delimiter = '.';



    EventEmitter.prototype.setMaxListeners = function (n) {

        if (n !== undefined) {

            this._maxListeners = n;

            if (!this._conf) this._conf = {};

            this._conf.maxListeners = n;

        }

    };



    EventEmitter.prototype.event = '';





    EventEmitter.prototype.once = function (event, fn) {

        return this._once(event, fn, false);

    };



    EventEmitter.prototype.prependOnceListener = function (event, fn) {

        return this._once(event, fn, true);

    };



    EventEmitter.prototype._once = function (event, fn, prepend) {

        this._many(event, 1, fn, prepend);

        return this;

    };



    EventEmitter.prototype.many = function (event, ttl, fn) {

        return this._many(event, ttl, fn, false);

    }



    EventEmitter.prototype.prependMany = function (event, ttl, fn) {

        return this._many(event, ttl, fn, true);

    }



    EventEmitter.prototype._many = function (event, ttl, fn, prepend) {

        var self = this;



        if (typeof fn !== 'function') {

            throw new Error('many only accepts instances of Function');

        }



        function listener() {

            if (--ttl === 0) {

                self.off(event, listener);

            }

            return fn.apply(this, arguments);

        }



        listener._origin = fn;



        this._on(event, listener, prepend);



        return self;

    };



    EventEmitter.prototype.emit = function () {



        this._events || init.call(this);



        var type = arguments[0];



        if (type === 'newListener' && !this.newListener) {

            if (!this._events.newListener) {

                return false;

            }

        }



        var al = arguments.length;

        var args, l, i, j;

        var handler;



        if (this._all && this._all.length) {

            handler = this._all.slice();

            if (al > 3) {

                args = new Array(al);

                for (j = 0; j < al; j++) args[j] = arguments[j];

            }



            for (i = 0, l = handler.length; i < l; i++) {

                this.event = type;

                switch (al) {

                    case 1:

                        handler[i].call(this, type);

                        break;

                    case 2:

                        handler[i].call(this, type, arguments[1]);

                        break;

                    case 3:

                        handler[i].call(this, type, arguments[1], arguments[2]);

                        break;

                    default:

                        handler[i].apply(this, args);

                }

            }

        }



        if (this.wildcard) {

            handler = [];

            var ns = typeof type === 'string' ? type.split(this.delimiter) : type.slice();

            searchListenerTree.call(this, handler, ns, this.listenerTree, 0);

        } else {

            handler = this._events[type];

            if (typeof handler === 'function') {

                this.event = type;

                switch (al) {

                    case 1:

                        handler.call(this);

                        break;

                    case 2:

                        handler.call(this, arguments[1]);

                        break;

                    case 3:

                        handler.call(this, arguments[1], arguments[2]);

                        break;

                    default:

                        args = new Array(al - 1);

                        for (j = 1; j < al; j++) args[j - 1] = arguments[j];

                        handler.apply(this, args);

                }

                return true;

            } else if (handler) {

                // need to make copy of handlers because list can change in the middle

                // of emit call

                handler = handler.slice();

            }

        }



        if (handler && handler.length) {

            if (al > 3) {

                args = new Array(al - 1);

                for (j = 1; j < al; j++) args[j - 1] = arguments[j];

            }

            for (i = 0, l = handler.length; i < l; i++) {

                this.event = type;

                switch (al) {

                    case 1:

                        handler[i].call(this);

                        break;

                    case 2:

                        handler[i].call(this, arguments[1]);

                        break;

                    case 3:

                        handler[i].call(this, arguments[1], arguments[2]);

                        break;

                    default:

                        handler[i].apply(this, args);

                }

            }

            return true;

        } else if (!this._all && type === 'error') {

            if (arguments[1] instanceof Error) {

                throw arguments[1]; // Unhandled 'error' event

            } else {

                throw new Error("Uncaught, unspecified 'error' event.");

            }

            return false;

        }



        return !!this._all;

    };



    EventEmitter.prototype.emitAsync = function () {



        this._events || init.call(this);



        var type = arguments[0];



        if (type === 'newListener' && !this.newListener) {

            if (!this._events.newListener) { return Promise.resolve([false]); }

        }



        var promises = [];



        var al = arguments.length;

        var args, l, i, j;

        var handler;



        if (this._all) {

            if (al > 3) {

                args = new Array(al);

                for (j = 1; j < al; j++) args[j] = arguments[j];

            }

            for (i = 0, l = this._all.length; i < l; i++) {

                this.event = type;

                switch (al) {

                    case 1:

                        promises.push(this._all[i].call(this, type));

                        break;

                    case 2:

                        promises.push(this._all[i].call(this, type, arguments[1]));

                        break;

                    case 3:

                        promises.push(this._all[i].call(this, type, arguments[1], arguments[2]));

                        break;

                    default:

                        promises.push(this._all[i].apply(this, args));

                }

            }

        }



        if (this.wildcard) {

            handler = [];

            var ns = typeof type === 'string' ? type.split(this.delimiter) : type.slice();

            searchListenerTree.call(this, handler, ns, this.listenerTree, 0);

        } else {

            handler = this._events[type];

        }



        if (typeof handler === 'function') {

            this.event = type;

            switch (al) {

                case 1:

                    promises.push(handler.call(this));

                    break;

                case 2:

                    promises.push(handler.call(this, arguments[1]));

                    break;

                case 3:

                    promises.push(handler.call(this, arguments[1], arguments[2]));

                    break;

                default:

                    args = new Array(al - 1);

                    for (j = 1; j < al; j++) args[j - 1] = arguments[j];

                    promises.push(handler.apply(this, args));

            }

        } else if (handler && handler.length) {

            handler = handler.slice();

            if (al > 3) {

                args = new Array(al - 1);

                for (j = 1; j < al; j++) args[j - 1] = arguments[j];

            }

            for (i = 0, l = handler.length; i < l; i++) {

                this.event = type;

                switch (al) {

                    case 1:

                        promises.push(handler[i].call(this));

                        break;

                    case 2:

                        promises.push(handler[i].call(this, arguments[1]));

                        break;

                    case 3:

                        promises.push(handler[i].call(this, arguments[1], arguments[2]));

                        break;

                    default:

                        promises.push(handler[i].apply(this, args));

                }

            }

        } else if (!this._all && type === 'error') {

            if (arguments[1] instanceof Error) {

                return Promise.reject(arguments[1]); // Unhandled 'error' event

            } else {

                return Promise.reject("Uncaught, unspecified 'error' event.");

            }

        }



        return Promise.all(promises);

    };



    EventEmitter.prototype.on = function (type, listener) {

        return this._on(type, listener, false);

    };



    EventEmitter.prototype.prependListener = function (type, listener) {

        return this._on(type, listener, true);

    };



    EventEmitter.prototype.onAny = function (fn) {

        return this._onAny(fn, false);

    };



    EventEmitter.prototype.prependAny = function (fn) {

        return this._onAny(fn, true);

    };



    EventEmitter.prototype.addListener = EventEmitter.prototype.on;



    EventEmitter.prototype._onAny = function (fn, prepend) {

        if (typeof fn !== 'function') {

            throw new Error('onAny only accepts instances of Function');

        }



        if (!this._all) {

            this._all = [];

        }



        // Add the function to the event listener collection.

        if (prepend) {

            this._all.unshift(fn);

        } else {

            this._all.push(fn);

        }



        return this;

    }



    EventEmitter.prototype._on = function (type, listener, prepend) {

        if (typeof type === 'function') {

            this._onAny(type, listener);

            return this;

        }



        if (typeof listener !== 'function') {

            throw new Error('on only accepts instances of Function');

        }

        this._events || init.call(this);



        // To avoid recursion in the case that type == "newListeners"! Before

        // adding it to the listeners, first emit "newListeners".

        this.emit('newListener', type, listener);



        if (this.wildcard) {

            growListenerTree.call(this, type, listener);

            return this;

        }



        if (!this._events[type]) {

            // Optimize the case of one listener. Don't need the extra array object.

            this._events[type] = listener;

        }

        else {

            if (typeof this._events[type] === 'function') {

                // Change to array.

                this._events[type] = [this._events[type]];

            }



            // If we've already got an array, just add

            if (prepend) {

                this._events[type].unshift(listener);

            } else {

                this._events[type].push(listener);

            }



            // Check for listener leak

            if (

              !this._events[type].warned &&

              this._maxListeners > 0 &&

              this._events[type].length > this._maxListeners

            ) {

                this._events[type].warned = true;

                logPossibleMemoryLeak.call(this, this._events[type].length, type);

            }

        }



        return this;

    }



    EventEmitter.prototype.off = function (type, listener) {

        if (typeof listener !== 'function') {

            throw new Error('removeListener only takes instances of Function');

        }



        var handlers, leafs = [];



        if (this.wildcard) {

            var ns = typeof type === 'string' ? type.split(this.delimiter) : type.slice();

            leafs = searchListenerTree.call(this, null, ns, this.listenerTree, 0);

        }

        else {

            // does not use listeners(), so no side effect of creating _events[type]

            if (!this._events[type]) return this;

            handlers = this._events[type];

            leafs.push({ _listeners: handlers });

        }



        for (var iLeaf = 0; iLeaf < leafs.length; iLeaf++) {

            var leaf = leafs[iLeaf];

            handlers = leaf._listeners;

            if (isArray(handlers)) {



                var position = -1;



                for (var i = 0, length = handlers.length; i < length; i++) {

                    if (handlers[i] === listener ||

                      (handlers[i].listener && handlers[i].listener === listener) ||

                      (handlers[i]._origin && handlers[i]._origin === listener)) {

                        position = i;

                        break;

                    }

                }



                if (position < 0) {

                    continue;

                }



                if (this.wildcard) {

                    leaf._listeners.splice(position, 1);

                }

                else {

                    this._events[type].splice(position, 1);

                }



                if (handlers.length === 0) {

                    if (this.wildcard) {

                        delete leaf._listeners;

                    }

                    else {

                        delete this._events[type];

                    }

                }



                this.emit("removeListener", type, listener);



                return this;

            }

            else if (handlers === listener ||

              (handlers.listener && handlers.listener === listener) ||

              (handlers._origin && handlers._origin === listener)) {

                if (this.wildcard) {

                    delete leaf._listeners;

                }

                else {

                    delete this._events[type];

                }



                this.emit("removeListener", type, listener);

            }

        }



        function recursivelyGarbageCollect(root) {

            if (root === undefined) {

                return;

            }

            var keys = Object.keys(root);

            for (var i in keys) {

                var key = keys[i];

                var obj = root[key];

                if ((obj instanceof Function) || (typeof obj !== "object") || (obj === null))

                    continue;

                if (Object.keys(obj).length > 0) {

                    recursivelyGarbageCollect(root[key]);

                }

                if (Object.keys(obj).length === 0) {

                    delete root[key];

                }

            }

        }

        recursivelyGarbageCollect(this.listenerTree);



        return this;

    };



    EventEmitter.prototype.offAny = function (fn) {

        var i = 0, l = 0, fns;

        if (fn && this._all && this._all.length > 0) {

            fns = this._all;

            for (i = 0, l = fns.length; i < l; i++) {

                if (fn === fns[i]) {

                    fns.splice(i, 1);

                    this.emit("removeListenerAny", fn);

                    return this;

                }

            }

        } else {

            fns = this._all;

            for (i = 0, l = fns.length; i < l; i++)

                this.emit("removeListenerAny", fns[i]);

            this._all = [];

        }

        return this;

    };



    EventEmitter.prototype.removeListener = EventEmitter.prototype.off;



    EventEmitter.prototype.removeAllListeners = function (type) {

        if (arguments.length === 0) {

            !this._events || init.call(this);

            return this;

        }



        if (this.wildcard) {

            var ns = typeof type === 'string' ? type.split(this.delimiter) : type.slice();

            var leafs = searchListenerTree.call(this, null, ns, this.listenerTree, 0);



            for (var iLeaf = 0; iLeaf < leafs.length; iLeaf++) {

                var leaf = leafs[iLeaf];

                leaf._listeners = null;

            }

        }

        else if (this._events) {

            this._events[type] = null;

        }

        return this;

    };



    EventEmitter.prototype.listeners = function (type) {

        if (this.wildcard) {

            var handlers = [];

            var ns = typeof type === 'string' ? type.split(this.delimiter) : type.slice();

            searchListenerTree.call(this, handlers, ns, this.listenerTree, 0);

            return handlers;

        }



        this._events || init.call(this);



        if (!this._events[type]) this._events[type] = [];

        if (!isArray(this._events[type])) {

            this._events[type] = [this._events[type]];

        }

        return this._events[type];

    };



    EventEmitter.prototype.eventNames = function () {

        return Object.keys(this._events);

    }



    EventEmitter.prototype.listenerCount = function (type) {

        return this.listeners(type).length;

    };



    EventEmitter.prototype.listenersAny = function () {



        if (this._all) {

            return this._all;

        }

        else {

            return [];

        }



    };



    if (typeof define === 'function' && define.amd) {

        // AMD. Register as an anonymous module.

        define(function () {

            return EventEmitter;

        });

    } else if (typeof exports === 'object') {

        // CommonJS

        module.exports = EventEmitter;

    }

    else {

        // Browser global.

        window.EventEmitter2 = EventEmitter;

    }

}();